package com.nowcoder.topic.dp.hard;

import java.util.Arrays;

/**
 * NC187 压缩字符串(二)
 * @author d3y1
 */
public class NC187{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param s string字符串
     * @param k int整型
     * @return int整型
     */
    public int compressString (String s, int k) {
        return solution(s, k);
    }

    /**
     * 动态规划
     *
     * dp[i][j]表示字符串前i个字符删除j个字符后的最小压缩长度  , j<=k&&j<=i
     *
     * dp[0][0] = 0
     *
     * same: 从第i个字符依次向左统计 与第i个字符相同的个数
     * diff: 从第i个字符依次向左统计 与第i个字符不同的个数(将被删除)
     *
     * step 1
     * dp[i][j] = dp[i-1][j-1]  , j>0
     * step 2
     * dp[i][j] = Math.min(dp[i][j], dp[m-1][j-diff]+calculate(same))  , 0<m<=i && diff<=j
     *
     * i:   0 1 2 3 4 5 6 7 8 9
     * s:     a a b a a a c c c
     * k=0  0 1 2 3 4 5 5 6 7 7
     * k=1    0 1 2 2 2 2 3 4 4
     * k=2      0 1 2 2 2 2 3 4
     * k=3        0 1 2 2 2 2 3
     *
     * @param s
     * @param k
     * @return
     */
    private int solution(String s, int k){
        int n = s.length();

        int[][] dp = new int[n+1][k+1];

        // init
        for(int i=0; i<=n; i++){
            // >>1 防止溢出
            Arrays.fill(dp[i], Integer.MAX_VALUE>>1);
        }
        dp[0][0] = 0;

        for(int i=1; i<=n; i++){
            for(int j=0; j<=k&&j<=i; j++){
                if(j > 0){
                    dp[i][j] = dp[i-1][j-1];
                }
                // 从第i个字符依次向左统计 与第i个字符相同的个数
                int same = 0;
                // 从第i个字符依次向左统计 与第i个字符不同的个数
                int diff = 0;
                for(int m=i; 0<m&&diff<=j; m--){
                    if(s.charAt(m-1) == s.charAt(i-1)){
                        same++;
                        dp[i][j] = Math.min(dp[i][j], dp[m-1][j-diff]+calculate(same));
                    }else{
                        diff++;
                    }
                }
            }
        }

        return dp[n][k];
    }

    /**
     * 计算压缩后的长度
     * @param same 相同字符长度
     * @return
     */
    private int calculate(int same){
        if(same == 1){
            return 1;
        }
        if(same < 10){
            return 2;
        }
        if(same < 100){
            return 3;
        }
        return 4;
    }
}